﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using DirectCanvas;
using DirectCanvas.Misc;
using WindowsFormsTest.Demos;
using WindowsFormsTest.Demos.CompositorDemo;
using WindowsFormsTest.Demos.EffectsDemo;
using WindowsFormsTest.Demos.GeometryDemo;
using WPFTestApp.Demos.EffectsDemo;
using DirectCanvas.Scenes;

namespace WPFTestApp
{
    public partial class MainWindow : Window
    {
        private DirectCanvasFactory m_directCanvasFactory;
        private WPFPresenter m_presenter;

        private Scene _m_scene;
        private Scene m_scene
        {
            get
            {
                return _m_scene;
            }
            set
            {
                _m_scene = value;
                if (m_presenter != null)
                {
                    m_presenter.CurrentScene = value;
                }
            }
        }
        private PixelShaderScene m_shaderScene;
        private GeometryScene m_geometryScene;
        private CompositorScene m_compositorScene;
        private SuperBlur m_superBlurScene;
        private TransitionEffectScene m_transitionScene;

        private object lockObj = new object();
        Mutex mutex = new Mutex();

        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
            SizeChanged += MainWindow_SizeChanged;
            Blake.NUI.WPF.Touch.NativeTouchDevice.RegisterEvents(this);
        }

        private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (m_presenter == null)
                return;

            m_presenter.SetSize((int)ActualWidth, (int)ActualHeight);
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            InitDirectCanvas();

            MouseDown += MainWindow_MouseDown;
            MouseUp += MainWindow_MouseUp;
            PreviewMouseMove += MainWindow_PreviewMouseMove;

            TouchDown += MainWindow_TouchDownMove;
            TouchMove += MainWindow_TouchDownMove;
            TouchUp += MainWindow_TouchUp;

            //Enable to test on another thread
            var t = new Thread(RenderLoop);
            t.IsBackground = true;
            //t.Start();

            //CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

        }

        private void RenderLoop()
        {
            while (true)
            {
                Dispatcher.Invoke((Action)Render, System.Windows.Threading.DispatcherPriority.Render);
                //Render();
                Thread.Sleep(10);
            }
        }

        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            Present();
            //this.InvalidateVisual();
        }

        private void Render()
        {
            //mutex.WaitOne();
            //m_scene.Render();
            m_presenter.Present();
            //mutex.ReleaseMutex();
            //this.InvalidateVisual();
        }

        private void Present()
        {
            //if (!mutex.WaitOne(0))
            //{
            //    return;
            //}
            m_scene.Render();
            m_presenter.Present();
            //mutex.ReleaseMutex();
        }

        private void MainWindow_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            var pos = e.GetPosition(this);
            var point = new PointF((float)pos.X, (float)pos.Y);
            var status = InputStatus.Up;
            if (e.LeftButton == MouseButtonState.Pressed)
                status = InputStatus.Down;
            m_scene.SetInputState(0, status, point);
        }

        private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed)
                return;
            var pos = e.GetPosition(this);
            var point = new PointF((float)pos.X, (float)pos.Y);

            m_scene.SetInputState(0, InputStatus.Down, point);
        }

        private void MainWindow_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed)
                return;
            var pos = e.GetPosition(this);
            var point = new PointF((float)pos.X, (float)pos.Y);
            m_scene.SetInputState(0, InputStatus.Up, point);
        }

        private void MainWindow_TouchDownMove(object sender, TouchEventArgs e)
        {
            var pos = e.GetTouchPoint(this).Position;
            var point = new PointF((float)pos.X, (float)pos.Y);
            m_scene.SetInputState(e.TouchDevice.Id, InputStatus.Down, point);

            e.Handled = true;
        }

        private void MainWindow_TouchUp(object sender, TouchEventArgs e)
        {
            var pos = e.GetTouchPoint(this).Position;
            var point = new PointF((float)pos.X, (float)pos.Y);
            m_scene.SetInputState(e.TouchDevice.Id, InputStatus.Up, point);
            e.Handled = true;
        }
        private void InitDirectCanvas()
        {
            m_directCanvasFactory = new DirectCanvasFactory();

            /* Create a new WindowsFromsPresenter, passing it our factory 
             * and our Winforms control that we want to render to */
            m_presenter = new WPFPresenter(m_directCanvasFactory,
                                           (int)Width /* Pixel width of our presenter */,
                                           (int)Height /* Pixel height of our presenter */,
                                           wpfImage /* The WPF Image to render to */);
            m_presenter.CurrentScene = m_scene;
            m_presenter.StartRendering();

            m_shaderScene = new PixelShaderScene(m_presenter);
            m_geometryScene = new GeometryScene(m_presenter);
            m_compositorScene = new CompositorScene(m_presenter);
            m_superBlurScene = new SuperBlur(m_presenter);
            m_transitionScene = new TransitionEffectScene(m_presenter);

            m_scene = m_geometryScene;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (m_shaderScene != null)
                m_scene = m_shaderScene;
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (m_geometryScene != null)
                m_scene = m_geometryScene;
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            if (m_compositorScene != null)
                m_scene = m_compositorScene;
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            if (m_superBlurScene != null)
                m_scene = m_superBlurScene;
        }

        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            if (m_superBlurScene != null)
                m_scene = m_transitionScene;
        }
    }
}
